package com.weseal.aop;

import com.weseal.exception.BaseException;
import com.weseal.response.CommonResult;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.lang.reflect.Method;

/**
 * @author weseal
 * @title
 * @description
 * @usage
 * @copyright Copyright 2014  rrmj Corporation. All rights reserved.
 * @company 上海众多美网络科技有限公司
 * @create 2017/9/11
 */

@Aspect
@Component
public class ExceptionAspect implements InitializingBean {
	private static final Logger logger = Logger.getLogger(ExceptionAspect.class);
	/**
	 * 所有带RequestMapping注解的方法
	 */
	private final static String el = "@annotation(org.springframework.web.bind.annotation.RequestMapping)";

	private final static String lineSeparator = System.getProperty("line.separator", "\n");

	@Before(el)
	public void before(JoinPoint jp) {
		logger.info("into exceptionAspect");
	}

	@After(el)
	public void after() {
	}


	@AfterThrowing(value = el, throwing = "ex")
	public void afterThrowing(Throwable ex) {
		logger.error(ex.getMessage());
	}


	@Around(el)
	public Object around(ProceedingJoinPoint p) throws IOException {
		Object result = null;
		MethodSignature methodSignature = (MethodSignature) p.getSignature();
		Method method = methodSignature.getMethod();
		boolean jsonObject = (null != AnnotationUtils.findAnnotation(method, ResponseBody.class));
		try {
			result = p.proceed();
		} catch (BaseException e) {
			fillLogin(methodSignature, e.getCode(), e.getMessage());
			return jsonObject ? CommonResult.errorInstant(e) : "404";
		} catch (org.apache.shiro.authc.AuthenticationException e) {
			fillLogin(methodSignature, "", e.getMessage());
			return jsonObject ? CommonResult.errorInstant((BaseException) e.getCause()) : "404";
		} catch (Throwable throwable) {
			StringBuffer errorStr = new StringBuffer("***********************************************");
			errorStr.append(lineSeparator);
			errorStr.append("    ").append(throwable.toString()).append(" : ").append(throwable.getMessage()).append(lineSeparator);
			StackTraceElement[] stackTraceElements = throwable.getStackTrace();
			for (StackTraceElement stackTraceElement : stackTraceElements) {
				String className = stackTraceElement.getClassName();
				String methodName = stackTraceElement.getMethodName();
				Integer lineNumber = stackTraceElement.getLineNumber();
				errorStr.append("    ").append(className).append(".")
						.append(methodName).append("(").append(lineNumber).append(")").append(lineSeparator);
			}
			logger.error(errorStr.toString());
			return jsonObject ? CommonResult.errorInstant(throwable) : "404";
		}
		return result;
	}

	private void fillLogin(MethodSignature methodSignature, String code, String message) {
		StringBuffer errorStr = new StringBuffer("errorCode : " + code + ", msg : " + message);
		errorStr.append(lineSeparator);
		errorStr.append(getKeyPre(methodSignature));
		errorStr.append(lineSeparator);
		logger.error(errorStr.toString());
	}

	private String getKeyPre(MethodSignature methodSignature) {
		Method method = methodSignature.getMethod();
		String className = methodSignature.getDeclaringTypeName();
		String methodName = method.getName();
		return className + "." + methodName;
	}


	@Override
	public void afterPropertiesSet() throws Exception {
		logger.info("init exceptionAspect");
	}
}
